feat(policy): rag-policy package — PolicyEngine PDP + coverage linter (Step 1.1c) - #46
Merged
officialCodeWork merged 1 commit intoMay 24, 2026
Conversation
officialCodeWork
force-pushed
the
build/phase-1/step-1.1c-policy-engine-package
branch
from
May 24, 2026 06:55
aff239a to
dff5a01
Compare
2 tasks
… (Step 1.1c)
New workspace package packages/policy/ (import root rag_policy v0.1.0).
Establishes the single Policy Decision Point ADR-0005 calls for: every
retrieval / ingest / egress code path consults PolicyEngine, and a CI
linter fails when a governance-relevant SPI call lands without an
adjacent consultation.
Surface
- PolicyEngine ABC: async evaluate(ctx, decision, subject) -> PolicyResult
and async filter_pushdown(ctx, decision) -> FilterExpr.
- NoopPolicyEngine: always-ALLOW; filter_pushdown still emits a
tenant-scoped And(Eq("tenant_id", ...)) so backends never cross-tenant
leak even with the noop loaded.
- PolicyWriter facade (mirrors AuditWriter): delegates to engine, emits
policy.decision structured log via rag-observability.
- PolicyDecision enum: read_chunk / ingest_doc / egress_text /
quota_check / rate_limit / execute_plan.
- PolicyResult: frozen union (allow / deny(reason) / transform(subject))
with is_allow / is_deny / is_transform / transformed_or helpers.
- QuotaSubject / RateLimitSubject for the non-Chunk decision subjects.
- FilterExpr mini-language (Eq, AnyIn, And, Or, Not, TrueExpr):
discriminated-union of frozen Pydantic models; backends translate to
native filter languages.
Coverage linter
- tests/policy/coverage.py greps for retrieve_ids / hydrate / bulk_index
/ stream_index / bulk_embed / .complete call sites without an adjacent
PolicyEngine / PolicyWriter marker. File-allowlist at top; failures
block CI. Consumers (gateway, ingest) shrink the allowlist as they
wire the PDP in. Future Step 1.1f tightens to call-pattern matching.
- Collected via pytest python_files extended to include coverage.py.
Wiring
- packages/policy added to [tool.uv.workspace].members and to pytest
pythonpath in root pyproject.toml.
- Dependencies: rag-core + rag-observability only (matches backends
precedent; CLAUDE.md graph: policy -> core).
Tests + gates
- 20 conformance tests under tests/contract/test_policy_engine.py.
- 1 coverage-linter run under tests/policy/coverage.py.
- ruff + mypy --strict (83 source files, +7 from 1.1b) + RAG001 logging
check all green; full non-integration suite 528 tests pass.
Docs
- New docs/reference/rag-policy.md (Overview / Usage / Internals /
Extension points), docs/README.md index updated. ADR-0005 and
docs/architecture/policy-engine.md already match the shipped shape.
TRACKER housekeeping
- Step 1.1c flipped to done; Next action set to 1.1d (Pipeline +
Batcher primitives).
- PR history table: added rows for #44 (1.1a) and #45 (1.1b) which
were missed when those steps merged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
officialCodeWork
force-pushed
the
build/phase-1/step-1.1c-policy-engine-package
branch
from
May 24, 2026 07:14
dff5a01 to
06b9aa9
Compare
1 task
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Step 1.1c of the Phase 1 architecture-refactor window. Lands the
Policy Decision Point ADR-0005 calls for: a single auditable surface
that every retrieval / ingest / egress code path consults, plus a CI
linter that fails when a new governance-relevant call site bypasses it.
packages/policy/(rag-policyv0.1.0,import root
rag_policy). Depends on rag-core + rag-observability only(matches the dependency graph in CLAUDE.md).
PolicyEngineABC —async evaluate(ctx, decision, subject) -> PolicyResultandasync filter_pushdown(ctx, decision) -> FilterExpr.NoopPolicyEngine— always-ALLOW reference impl;filter_pushdownstill emits
And(Eq("tenant_id", str(ctx.tenant_id)))so retrievalbackends cannot cross-tenant leak even with the noop loaded.
PolicyWriterfacade (mirrorsAuditWriter) — delegates to theengine and emits a
policy.decisionstructured-log entry viarag_observability.logging. Consumers should reach for the writer.PolicyDecisionenum:read_chunk/ingest_doc/egress_text/
quota_check/rate_limit/execute_plan.PolicyResultfrozen union (allow/deny(reason)/transform(subject)) with predicate helpers.FilterExprmini-language (Eq,AnyIn,And,Or,Not,TrueExpr) — discriminated-union of frozen Pydantic models, returnedby
filter_pushdownand consumed by retrieval backends.tests/policy/coverage.pygreps forretrieve_ids/hydrate/bulk_index/stream_index/bulk_embed/.complete(call sites without an adjacentPolicyEngine/PolicyWritermarker. File-allowlist at the top;consumers (gateway, ingest) shrink the allowlist as they wire the PDP
in. A future Step 1.1f tightens the linter from file-allowlist to
call-pattern matching.
Step 6.4 (ACL egress verifier as a second layer) is rendered redundant
by this PDP — see ADR-0005. The TRACKER entry for 6.4 will flip to
"Superseded by ADR-0005" in the Phase 6 refactor pass.
Documentation
(Overview / Usage / Internals / Extension points).
docs/architecture/policy-engine.mdalready describe theshipped shape — no changes needed there.
Test plan
(+7 from Step 1.1b)
528 passed, 1 skipped (20 new conformance + 1 coverage linter)
for noop + abstracts + real backends).
TRACKER housekeeping rolled in
action set to 1.1d — Pipeline + Batcher primitives.
which were missed when those merged.
🤖 Generated with Claude Code